﻿using ICSharpCode.SharpZipLib.Zip;
using Microsoft.Web.WebView2.Core;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.IO.Pipes;
using System.Linq;
using System.Net.Http.Headers;
using System.Security.AccessControl;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using TS = Microsoft.Win32.TaskScheduler;

namespace TaskLiskFullscreen
{
    internal static class Program
    {

        const string mutexId = "GenshinTodoManager_0_{EC9BC5A8-6187-4619-BA88-3051E7371BBB}";
        const string pipeId = "GenshinTodoManager_EC9BC5A861874619BA883051E7371BBB";


        public static IPakFile HtDocs = null;
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {



            Environment.CurrentDirectory = Path.GetDirectoryName(Application.ExecutablePath);

            if (StartupArgs.ProcessStartupArgs(args))
            {
                return;
            }

            CheckDuplicate(args);
            Environment.Exit(0);
        }

        public static void CheckDuplicate(string[] args)
        {
            Mutex mutex = new Mutex(false, mutexId);
            try
            {
                if (new Func<bool>(() => {
                    try
                    {
                        return mutex.WaitOne(300, true);
                    }
                    catch (AbandonedMutexException)
                    {
                        return mutex.WaitOne(300, true);
                    }
                })())
                {
                    ContinueStartup(args);
                    return;
                }
                else
                {
                    SendSignalToExistingInstance();
                    return;
                }
            }
           
            finally
            {
                try
                {
                    mutex.ReleaseMutex();
                }
                catch { }
            }
        }

        public static void SendSignalToExistingInstance()
        {
            NamedPipeClientStream pipe = new NamedPipeClientStream(pipeId);
            pipe.Connect(3000);
            pipe.Close();
        }


        public static event EventHandler<EventArgs> ExternalRequireActivate;


        public static bool IsFirstLaunch = false;

        public static void ContinueStartup(string[] args)
        {

           
            new Thread(PipeMoniteringThread) { IsBackground = true }.Start();

            var htdocsMemoryStream = new MemoryStream(Properties.Resources.htdocs);
            HtDocs = new MyPakFile(htdocsMemoryStream);

#if DEBUG
            HtDocs.Dispose();
            HtDocs = new LocalDirRoot(Path.GetFullPath("../../wwwroot/"));
#endif
            // 外部修改接口
            var externalPack = Path.GetFullPath(Path.Combine(Application.StartupPath,"wwwroot"));
            if(Directory.Exists(externalPack) && File.Exists(Path.Combine(externalPack, "container.html")))
            {
                HtDocs.Dispose();
                HtDocs = new LocalDirRoot(externalPack);
            }
            PrepareWebview2RuntimeEnvironment();
            if (!Directory.Exists("app"))
            {
                Directory.CreateDirectory("app");
                IsFirstLaunch = true;
            }
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new FrmMain());
        }

        public static void PipeMoniteringThread()
        {
            PipeSecurity ps = new PipeSecurity(); 
            ps.AddAccessRule(new PipeAccessRule("Everyone", PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance, AccessControlType.Allow));
            ps.AddAccessRule(new PipeAccessRule("CREATOR OWNER", PipeAccessRights.FullControl, AccessControlType.Allow));
            ps.AddAccessRule(new PipeAccessRule("SYSTEM", PipeAccessRights.FullControl, AccessControlType.Allow));
            while (true)
            {
                NamedPipeServerStream namedPipeServerStream = new NamedPipeServerStream(pipeId, PipeDirection.InOut, 114,PipeTransmissionMode.Byte,PipeOptions.None,1024,1024,ps);
                namedPipeServerStream.WaitForConnection();
                Console.WriteLine("External activation required");
                namedPipeServerStream.Disconnect();
                namedPipeServerStream.Dispose();
                ExternalRequireActivate?.Invoke(null, EventArgs.Empty);
            }
        }

        public static class StartupArgs
        {

            /// <summary>
            /// 用于计划任务启动应用程序。程序运行之后，使用-min启动自身然后退出。防止笔记本因为切换到电池导致计划任务强行停止
            /// </summary>
            public static bool IsRunByAutorun = false;
            public const string FlagRunByAutorun = "--startup";
            /// <summary>
            /// 用于非管理员权限以管理员权限调用自身设置开机自启
            /// </summary>
            public static bool IsSettingAutorun = false;
            public const string FlagSetAutorun = "--set-autorun";
            /// <summary>
            /// 开启之后默认不显示窗口
            /// </summary>
            public static bool IsMinimized = false;
            public const string FlagMinimized = "-min";


            public static bool ProcessStartupArgs(string[] args)
            {
                IsRunByAutorun = args.Contains(FlagRunByAutorun);
                IsSettingAutorun = args.Contains(FlagSetAutorun);
                IsMinimized = args.Contains(FlagMinimized);

                if (IsRunByAutorun)
                {


                    HandleAutoStart();
                    return true;
                }

                if (IsSettingAutorun)
                {

                    SetAutoStart();
                    return true;
                }

                return false;
            }

            public const string AutoRunId = "GenshinTodoManager_EC9BC5A861874619BA883051E7371BBB";

            public static void SetAutoStart()
            {
                TS.TaskService taskService = TS.TaskService.Instance;
                var taskinfo = taskService.NewTask();
                taskinfo.RegistrationInfo.Description = "Genshin Todo Manager 的开机自启项";
                taskinfo.Triggers.Add(new TS.LogonTrigger()
                {
                    ExecutionTimeLimit = TimeSpan.FromDays(730),
                    Enabled = true,
                });
                taskinfo.Actions.Add(Process.GetCurrentProcess().MainModule.FileName, FlagRunByAutorun, Environment.CurrentDirectory);
                taskinfo.Principal.RunLevel = TS.TaskRunLevel.Highest;
                taskinfo.Principal.LogonType = TS.TaskLogonType.InteractiveToken;

                taskinfo.Settings.DisallowStartIfOnBatteries = false;
                taskinfo.Settings.ExecutionTimeLimit = TimeSpan.FromDays(1);
                if(taskService.RootFolder.Tasks.Any(t => t.Name == AutoRunId))
                {
                    taskService.RootFolder.DeleteTask(AutoRunId, false);
                    MessageBox.Show("已取消设置开机自启。");
                }
                else
                {
                    taskService.RootFolder.RegisterTaskDefinition(AutoRunId, taskinfo);
                    MessageBox.Show("已设置开机自启。");
                }
            }

            public static void HandleAutoStart()
            {
                ProcessStartInfo psi = new ProcessStartInfo(Application.ExecutablePath, FlagMinimized);
                psi.WorkingDirectory = Environment.CurrentDirectory;
                Process.Start(psi);
            }

        }


        public interface IPakFile : IDisposable
        {
            IPakFile Overrides { get; set; }

            Stream OpenRead(string path);
        }

        public class MyPakFile : IPakFile
        {

            public string Tag = "";
            public List<string> files = new List<string>();
            ZipFile src;

            public IPakFile Overrides { get; set; }

            public MyPakFile(Stream stream)
            {
                src = new ZipFile(stream);
                System.Collections.IEnumerator en = src.GetEnumerator();
                while (en.MoveNext())
                {
                    ZipEntry ze = en.Current as ZipEntry;
                    if (ze != null)
                    {
                        files.Add(ze.Name);
                        Console.WriteLine(ze.Name);
                    }
                }
            }

            public virtual Stream OpenRead(string filename)
            {
                if (Overrides != null)
                {
                    var r = Overrides.OpenRead(filename);
                    if (r != null)
                    {
                        return r;
                    }
                }
                if (files.Contains(filename) && !filename.EndsWith("/"))
                {
                    ZipEntry ze = src.GetEntry(filename);
                    return src.GetInputStream(ze);
                }
                return null;
            }

            public void Dispose()
            {
                ((IDisposable)src).Dispose();
            }
        }

        public class LocalDirRoot : IPakFile
        {
            private string root;
            public LocalDirRoot(string path)
            {
                root = path;
            }

            public IPakFile Overrides { get; set; }

            public void Dispose()
            {
            }

            public Stream OpenRead(string path)
            {
                string filepath = Path.Combine(root, path);
                if (!File.Exists(filepath))
                {
                    return null;
                }
                try
                {
                    MemoryStream ms = new MemoryStream();
                    using (FileStream fs = File.OpenRead(filepath))
                    {
                        fs.CopyTo(ms);
                    }
                    ms.Seek(0, SeekOrigin.Begin);
                    return ms;
                }
                catch (Exception)
                {
                    return null;
                }
            }
        }


        private static void PrepareWebview2RuntimeEnvironment()
        {
            string baseDir = Path.Combine(Environment.GetEnvironmentVariable("LOCALAPPDATA"), "GenshinTodoManager", "wvruntime_0");
            if (!Directory.Exists(baseDir)) { Directory.CreateDirectory(baseDir); }
            string flagFile = Path.Combine(baseDir, "runtime.ok");
            if (!File.Exists(flagFile))
            {
                using (ZipArchive zipArchive = new ZipArchive(new MemoryStream(Properties.Resources.runtimes), ZipArchiveMode.Read, false))
                {
                    foreach (var item in zipArchive.Entries)
                    {
                        if (item.FullName.EndsWith("/"))
                        {

                        }
                        else
                        {
                            string fileName = Path.Combine(baseDir, item.FullName);
                            string fileDir = Path.GetDirectoryName(fileName);
                            if (!Directory.Exists(fileDir)) { Directory.CreateDirectory(fileDir); }
                            using (FileStream fs = File.Create(fileName))
                            {
                                using (Stream s = item.Open())
                                {
                                    s.CopyTo(fs);
                                }
                            }
                        }
                    }
                    File.Create(flagFile).Close();
                }

            }

            if (Environment.Is64BitProcess)
            {
                CoreWebView2Environment.SetLoaderDllFolderPath(Path.Combine(baseDir, "runtimes", "win-x64", "native"));
            }
            else
            {

                CoreWebView2Environment.SetLoaderDllFolderPath(Path.Combine(baseDir, "runtimes", "win-x86", "native"));
            }

        }

    }
}
